package org.flint.data.structure.linkedlist;

import com.google.common.base.Preconditions;

/**
 * @author flint92
 */
public class LinkedList<E> {

    class Node {
        E e;
        Node next;

        Node(E e, Node next) {
            this.e = e;
            this.next = next;
        }

        public Node(E e) {
            this(e, null);
        }

        @Override
        public String toString() {
            return String.valueOf(e);
        }
    }

    private Node dummyHead;
    private int size;

    public LinkedList() {
        this.dummyHead = new Node(null, null);
        this.size = 0;
    }

    public int getSize() {
        return size;
    }

    public boolean isEmpty() {
        return this.size == 0;
    }

    /**
     * 添加元素
     *
     * @param e     元素
     * @param index 索引
     */
    public void add(E e, int index) {
        Preconditions.checkPositionIndex(index, size);
        Node prev = dummyHead;
        for (int i = 0; i < index; i++) {
            prev = prev.next;
        }

        prev.next = new Node(e, prev.next);
        size++;
    }

    /**
     * 头部添加元素
     *
     * @param e 元素
     */
    public void addFirst(E e) {
        add(e, 0);
    }

    /**
     * 尾部添加元素
     *
     * @param e 元素
     */
    public void addLast(E e) {
        add(e, size);
    }

    /**
     * 获取元素
     *
     * @param index 索引
     * @return 元素
     */
    public E get(int index) {
        Preconditions.checkElementIndex(index, size);

        Node curr = dummyHead.next;
        for (int i = 0; i < index; i++) {
            curr = curr.next;
        }
        return curr.e;
    }

    /**
     * @return 获取头元素
     */
    public E getFirst() {
        return get(0);
    }

    /**
     * @return 获取尾部元素
     */
    public E getLast() {
        return get(size - 1);
    }

    /**
     * 修改元素
     *
     * @param e     元素
     * @param index 索引位置
     */
    public void set(E e, int index) {
        Preconditions.checkElementIndex(index, size);
        Node curr = dummyHead.next;
        for (int i = 0; i < index; i++) {
            curr = curr.next;
        }
        curr.e = e;
    }

    /**
     * 查看链表中是否包含元素e
     *
     * @param e 元素e
     * @return bool
     */
    public boolean contains(E e) {
        Node curr = dummyHead.next;

        while (curr != null) {
            if (curr.e.equals(e)) {
                return true;
            }
            curr = curr.next;
        }

        return false;
    }

    /**
     * 删除操作
     *
     * @param index 索引值
     * @return 被删除元素
     */
    public E remove(int index) {
        Preconditions.checkElementIndex(index, size);

        Node pre = dummyHead.next;
        for (int i = 0; i < index; i++) {
            pre = pre.next;
        }

        Node retNode = pre.next;
        pre.next = retNode.next;
        retNode.next = null;
        size--;

        return retNode.e;
    }

    /**
     * 删除第一个元素
     *
     * @return 第一个元素
     */
    public E removeFirst() {
        return remove(0);
    }

    /**
     * 删除最后一个元素
     *
     * @return 最后一个元素
     */
    public E removeLast() {
        return remove(size - 1);
    }

}
